/**
 *
 */
package de.cbf.cam.dsa.person.birth_data_generator;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.jface.preference.IPreferenceStore;

import de.cbf.cam.dice.entities.RollDefinitionSum;
import de.cbf.cam.dice.logic.DiceRollerSum;
import de.cbf.cam.dsa.person.birth_data_generator.act.ActivatorBirthDataGenerator;
import de.cbf.cam.dsa.person.birth_data_generator.preferences.PreferenceConstants;
import de.cbf.cam.dsa.person.entities.PersonBaseDSA;
import de.cbf.cam.dsa.person.entities.PersonEyesDSA;
import de.cbf.cam.dsa.person.entities.PersonHairDSA;
import de.cbf.cam.dsa.person.extension.interfaces.AbstractNamedGenerator;
import de.cbf.cam.dsa.person.extension.interfaces.IBirthDataGenerator;
import de.cbf.cam.dsa.person.generator.PropertyConstants;
import de.cbf.cam.dsa.rcp.model.entities.MonthDSAEnum;
import de.cbf.cam.dsa.rcp.model.entities.RaceDSA;
import de.cbf.util.number_generator.RandomNumberGenerator;
import de.cbf.util.number_generator.interfaces.IProbabilitySpan;
import de.cbf.util.uuidheader.entities.EntityWeighted;
import de.cbf.util.uuidheader.entities.NamedEntity;

/**
 * @author salter
 *
 */
public class BirthDataGenerator extends AbstractNamedGenerator implements IBirthDataGenerator{
	private static final Log logger = LogFactory.getLog(BirthDataGenerator.class);

	protected RandomNumberGenerator rnd;

	protected IPreferenceStore prefs;

	public BirthDataGenerator() {
		super();
		rnd = RandomNumberGenerator.getInstance();
		setName("Birth Data Generator");
		prefs = ActivatorBirthDataGenerator.getDefault().getPreferenceStore();
	}

	@Override
	public void generateBirthDataForPerson(PersonBaseDSA person, RaceDSA race,Map<String,Object> properties) {
		//only generate if it is not generated
		if(person.getEyes() == null){
			//generate eye color information
			logger.debug("generating eyes information...");

			String eyeColor = chooseRandomText(race.getPossibleEyeColors());

			List<String> eyeSpecials = getEyeSpecials(race,person);

			PersonEyesDSA personEyes = new PersonEyesDSA();
			personEyes.setColor(eyeColor);
			personEyes.setSpecials(eyeSpecials);
			logger.debug("generated: "+personEyes.getEyeLooks());
			person.setEyes(personEyes);
		}

		if(person.getHair() == null){
			//generate hair color information
			logger.debug("generating hair information...");

			String hairColor = chooseRandomText(race.getPossibleHairColors());

			List<String> hairSpecials = getHairSpecials(race,person);

			PersonHairDSA personHair = new PersonHairDSA();
			personHair.setColor(hairColor);
			personHair.setSpecials(hairSpecials );
			logger.debug("generated: "+personHair.getHairLooks());
			person.setHair(personHair);

		}
		if(person.getHeight() == 0){
			//generate height information
			logger.debug("generating height information...");
			RollDefinitionSum rollDef = race.getHeigthRollDefinition();
			int diceResult = DiceRollerSum.rollSumDice(rollDef);
			logger.debug("generated: "+diceResult);
			person.setHeight(diceResult);
		}
		generateBirthDayMonthYear(person, properties);
	}

	public void generateBirthDayMonthYear(PersonBaseDSA person, Map<String, Object> properties){
		//generate birth day/month/year, month first, cause that specifies days in month
		if(person.getBirthmonth() == null){
			logger.debug("generating birthmonth information...");
			MonthDSAEnum[] months = MonthDSAEnum.values();
			int index = rnd.getRandomNumber(months.length);
			MonthDSAEnum chosenMonth = months[index];
			logger.debug("generated: "+chosenMonth);
			person.setBirthmonth(chosenMonth);
		}
		int daysInMonth = MonthDSAEnum.getDaysInMonth(person.getBirthmonth());
		if(person.getBirthday() == 0){
			logger.debug("generating birthday information...");
			int birthday = rnd.getRandomNumber(daysInMonth);
			birthday++;//add one as it would start with 0 else
			logger.debug("generated: "+birthday);
			person.setBirthday(birthday);
		}
		if(person.getBirthyear() == 0){
			logger.debug("generating birthyear information...");

			Object minAgeObject = properties.get(PropertyConstants.PROPERTY_MIN_AGE);
			Object maxAgeObject = properties.get(PropertyConstants.PROPERTY_MAX_AGE);
			Object currentYearObject = properties.get(PropertyConstants.PROPERTY_CURRENT_YEAR);
			Integer minAge = null;
			Integer maxAge = null;
			Long currentYear = null;
			//extract properties
			if (minAgeObject instanceof Integer) {
				minAge = (Integer) minAgeObject;
			}else{
				minAge = prefs.getInt(PreferenceConstants.P_DEFAULT_MIN_AGE);
				logger.error(PropertyConstants.PROPERTY_MIN_AGE+" not correctly set: "+minAgeObject+"\n" +
						"using default: "+minAge);
			}

			if (maxAgeObject instanceof Integer) {
				maxAge = (Integer) maxAgeObject;
			}else{
				maxAge = prefs.getInt(PreferenceConstants.P_DEFAULT_MAX_AGE);
				logger.error(PropertyConstants.PROPERTY_MAX_AGE+" not correctly set: "+maxAgeObject+"\n" +
						"using default: "+maxAge);
			}

			if (currentYearObject instanceof Long) {
				currentYear = (Long) currentYearObject;
			}else{
				currentYear = prefs.getLong(PreferenceConstants.P_DEFAULT_CURRENT_YEAR);
				logger.error(PropertyConstants.PROPERTY_CURRENT_YEAR+" not correctly set: "+currentYearObject+"\n" +
						"using default: "+currentYear);
			}
			logger.debug("calculating from: \n" +
					"minAge: " +minAge+"\n"+
					"maxAge: " +maxAge+"\n"+
					"currentYear: "+currentYear);
			//calculate
			Integer ageAdd = rnd.findRandomBetweenMinMax(minAge, maxAge);

			Long birthYear = currentYear-(ageAdd+minAge);
			logger.debug("generated birthYear: "+birthYear);
			person.setBirthyear(birthYear);
		}
	}

	protected String chooseRandomText(List<EntityWeighted> entities){
		String result = "";
		List<IProbabilitySpan> probableEntities = new ArrayList<IProbabilitySpan>();
		probableEntities.addAll(entities);
		IProbabilitySpan chosen = RandomNumberGenerator.findByProbability(probableEntities);
		if (chosen instanceof EntityWeighted) {
			EntityWeighted entityWeighted = (EntityWeighted) chosen;
			if (entityWeighted.getEntity() instanceof NamedEntity) {
				NamedEntity namedEntity = (NamedEntity) entityWeighted.getEntity();
				result = namedEntity.getName();
			}
		}
		return result;
	}


	private List<String> getEyeSpecials(RaceDSA race, PersonBaseDSA person) {
		List<String> result = new ArrayList<String>();
		//TODO find eye specials by chosenRace/age/person(character), possibly move this to own generator
		return result;
	}

	private List<String> getHairSpecials(RaceDSA race, PersonBaseDSA person) {
		List<String> result = new ArrayList<String>();
		//TODO find hair specials by chosenRace/chosenCulture/age/person(character), possibly move this to own generator
		return result;
	}
}
